 
  

 






<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html>

<!-- Mirrored from www.javapractices.com/topic/TopicAction.do;jsessionid=4FCCB481C702D708A7360133D128E359?Id=13 by HTTrack Website Copier/3.x [XR&CO'2010], Sun, 12 Jun 2011 17:27:38 GMT -->
<!-- Added by HTTrack --><meta http-equiv="content-type" content="text/html;charset=UTF-8"><!-- /Added by HTTrack -->
<head>
 <title>
  Java Practices -> Representing money
 </title>
 <link rel="stylesheet" type="text/css" href="../stylesheet8.css" media="all">
 
 <link rel="shortcut icon" href='../images/favicon.ico' type="image/vnd.microsoft.icon">
 <meta name="description" content="Concise presentations of java programming practices, tasks, and conventions, amply illustrated with syntax highlighted code examples.">
 
 <meta name='keywords' content='BigDecimal,currency,java,java programming,java practices,java idiom,java style,java design patterns,java coding conventions,'>
 
 
</head>
 
<body>


<div class='menu-bar'>
 
  <a href='../home/HomeAction.html' title='Table of Contents'>Home</a> |
  <a href='../vote/VoteSummaryAction-2.html' title='View Poll Results'>Poll</a> |
   
  <A href='../feedback/FeedbackAction451f-2.html?Operation=Show' title='Send Your Feedback'>Wiki</a> |
  <b><a href='../source/SourceAction-2.html' title='Grab Source Code'>Source Code</a></b><IMG class='no-margin' SRC="../images/goldstar.gif" ALT=""> |

  <a href='http://www.web4j.com/Java_Web_Application_Framework_Overview.jsp?From=1' title='Free Download - Java Web Application Framework'><b>WEB4J</b></a> |
  
  <a href='http://www.date4j.net/' title='Replacement for java.util.Date'><b>DATE4J</b></a> |

   <a href='../references/ReferencesAction-2.html' title='References'>Links</a>
   
  <form action='http://www.javapractices.com/search/SearchAction.do' method='get' class='search-form'>
   <input type='text' name='SearchTerms' value="" size=12 maxlength=50 class='search'>
   <input type='submit' value="Search">
  </form>
 
</div>

<P>



  

 






<p class="display-messages">

 

 

</p>


<div class="main-layout">
 
   

 




<div class='page-title'>Representing money</div>

<div class='main-body'>
 
<br>Representing money :
<ul>
<li>
use <tt><a href="http://java.sun.com/javase/6/docs/api/java/math/BigDecimal.html">BigDecimal</a></tt>,
<tt>int</tt>,
or <tt>long</tt> (<tt>BigDecimal</tt> is the recommended default) </li>


<li>
the <tt>int</tt> and <tt>long</tt> forms represent pennies (or the equivalent,
of course)</li>

<li>
<tt>BigDecimal</tt> is a little more inconvenient to use, but has built-in
rounding modes</li>

<li>
<tt>double</tt> or <tt>float</tt> are <a href="TopicActionb0f5-2.html">not recommended</a>, since they always carry small
rounding differences</li>

<li>
the <tt><a href="http://java.sun.com/javase/6/docs/api/java/util/Currency.html">Currency</a></tt>
class encapsulates standard identifiers for the world's currencies</li>
</ul>
&nbsp;Number of digits :
<ul>
<li>
<tt>&lt;=9</tt> : use <tt>int</tt>, <tt>long</tt> , or <tt>BigDecimal</tt></li>

<li>
<tt>&lt;=18</tt> : use <tt>long</tt> or <tt>BigDecimal</tt></li>

<li>
<tt>>18</tt> : use <tt>BigDecimal</tt></li>
</ul>
Reminders for <tt>BigDecimal</tt> :
<ul>
<li>
the recommended constructor is <tt>BigDecimal(String)</tt>, not <tt>BigDecimal(double)</tt>
- see <a href="http://java.sun.com/javase/6/docs/api/java/math/BigDecimal.html#BigDecimal(double)">javadoc</a></li>

<li>
<tt>BigDecimal</tt> objects are immutable - operations always return new
objects, and never modify the state of existing objects</li>

<li>the 
<a href="http://java.sun.com/javase/6/docs/api/java/math/BigDecimal.html#ROUND_HALF_EVEN">ROUND_HALF_EVEN</a>
style of <a href="http://en.wikipedia.org/wiki/Rounding">rounding</a> introduces the least bias. 
It is also called <em>bankers' rounding</em>, or <em>round-to-even</em>. 
</ul>
<b>Example 1</b>
<P>Example of using <tt>BigDecimal</tt> to perform monetary calculations :
<br>
<PRE>

<span class='keyword'>import</span> java.math.BigDecimal;
<span class='keyword'>import</span> java.util.Currency;

<span class='comment'>/**
* Example of typical calculations with monetary values, implemented with
* &lt;tt&gt;BigDecimal&lt;/tt&gt;.
*
* &lt;P&gt;This example is for a currency which has two decimal places.
*
* See
* http://java.sun.com/j2se/1.5.0/docs/api/java/math/BigDecimal.html
*
* Note in particular how the &lt;em&gt;default&lt;/em&gt; scale of the result of an
* operation is calculated from the scales of the two input numbers :
* &lt;ul&gt;
* &lt;li&gt; a + b : max[ scale(a), scale(b) ]
* &lt;li&gt; a - b : max[ scale(a), scale(b) ]
* &lt;li&gt; a * b : scale(a) + scale(b)
* &lt;li&gt; a / b : scale(a) - scale(b)
* &lt;/ul&gt;
*/</span>
<span class='keyword'>public</span> <span class='keyword'>final</span> <span class='keyword'>class</span> MoneyCalculation {

  <span class='comment'>/**
  * Simple test harness.
  *
  * Takes two numeric arguments, representing monetary values, in a form
  * which can be passed successfully to the &lt;tt&gt;BigDecimal(String)&lt;/tt&gt;
  * constructor (&lt;tt&gt;25.00, 25.0, 25&lt;/tt&gt;, etc).
  *
  * Note that the &lt;tt&gt;String&lt;/tt&gt; constructor is preferred for
  * &lt;tt&gt;BigDecimal&lt;/tt&gt;.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> <span class='keyword'>void</span> main(String... aArgs){
    BigDecimal amountOne = <span class='keyword'>new</span> BigDecimal(aArgs[<span class='literal'>0</span>]);
    BigDecimal amountTwo = <span class='keyword'>new</span> BigDecimal(aArgs[<span class='literal'>1</span>]);
    MoneyCalculation calc = <span class='keyword'>new</span> MoneyCalculation(amountOne, amountTwo);
    calc.doCalculations();
  }

  <span class='keyword'>public</span> MoneyCalculation(BigDecimal aAmountOne, BigDecimal aAmountTwo){
    fAmountOne = rounded(aAmountOne);
    fAmountTwo = rounded(aAmountTwo);
  }

  <span class='keyword'>public</span> <span class='keyword'>void</span> doCalculations() {
    log(<span class='literal'>"Amount One: "</span> + fAmountOne);
    log(<span class='literal'>"Amount Two: "</span> + fAmountTwo);
    log(<span class='literal'>"Sum : "</span> + getSum());
    log(<span class='literal'>"Difference : "</span> + getDifference());
    log(<span class='literal'>"Average : "</span> + getAverage());
    log(<span class='literal'>"5.25% of Amount One: "</span> + getPercentage());
    log(<span class='literal'>"Percent Change From Amount One to Two: "</span> + getPercentageChange());
  }

  <span class='comment'>// PRIVATE //
</span>
  <span class='keyword'>private</span> BigDecimal fAmountOne;
  <span class='keyword'>private</span> BigDecimal fAmountTwo;

  <span class='comment'>/**
  * Defined centrally, to allow for easy changes to the rounding mode.
  */</span>
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>int</span> ROUNDING_MODE = BigDecimal.ROUND_HALF_EVEN;

  <span class='comment'>/**
  * Number of decimals to retain. Also referred to as "scale".
  */</span>
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>int</span> DECIMALS = <span class='literal'>2</span>;
  <span class='comment'>//An alternate style for this value :
</span>  <span class='comment'>//private static int DECIMAL_PLACES =
</span>  <span class='comment'>//  Currency.getInstance("USD").getDefaultFractionDigits()
</span>  <span class='comment'>//;
</span>
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>int</span> EXTRA_DECIMALS = <span class='literal'>4</span>;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> BigDecimal TWO = <span class='keyword'>new</span> BigDecimal(<span class='literal'>"2"</span>);
  <span class='keyword'>private</span> <span class='keyword'>static</span> BigDecimal HUNDRED = <span class='keyword'>new</span> BigDecimal(<span class='literal'>"100"</span>);
  <span class='keyword'>private</span> <span class='keyword'>static</span> BigDecimal PERCENTAGE = <span class='keyword'>new</span> BigDecimal(<span class='literal'>"5.25"</span>);

  <span class='keyword'>private</span> <span class='keyword'>void</span> log(String aText){
    System.out.println(aText);
  }

  <span class='keyword'>private</span> BigDecimal getSum(){
    <span class='keyword'>return</span> fAmountOne.add(fAmountTwo);
  }

  <span class='keyword'>private</span> BigDecimal getDifference(){
    <span class='keyword'>return</span> fAmountTwo.subtract(fAmountOne);
  }

  <span class='keyword'>private</span> BigDecimal getAverage(){
    <span class='keyword'>return</span> getSum().divide(TWO, ROUNDING_MODE);
  }

  <span class='keyword'>private</span> BigDecimal getPercentage(){
    BigDecimal result = fAmountOne.multiply(PERCENTAGE);
    result = result.divide(HUNDRED, ROUNDING_MODE);
    <span class='keyword'>return</span> rounded(result);
  }

  <span class='keyword'>private</span> BigDecimal getPercentageChange(){
    BigDecimal fractionalChange = getDifference().divide(
      fAmountOne, EXTRA_DECIMALS, ROUNDING_MODE
    );
    <span class='keyword'>return</span> rounded( fractionalChange.multiply(HUNDRED) );
  }

  <span class='keyword'>private</span> BigDecimal rounded(BigDecimal aNumber){
    <span class='keyword'>return</span> aNumber.setScale(DECIMALS, ROUNDING_MODE);
  }
} 
</PRE>
<br>
<br>An example run gives :
<p><tt>>java -cp . MoneyCalculation 513.89 612.25</tt>
<br><tt>Amount One: 513.89</tt>
<br><tt>Amount Two: 612.25</tt>
<br><tt>Sum : 1126.14</tt>
<br><tt>Difference : 98.36</tt>
<br><tt>Average : 563.07</tt>
<br><tt>5.25% of Amount One: 26.98</tt>
<br><tt>Percent Change From Amount One to Two: 19.14</tt>

<P><b>Example 2</b>
<P>The lack of an actual <tt>Money</tt> class in the standard JDK libraries is frustrating.
Such a class would have some nice advantages :
<ul>
 <li>the name <tt>Money</tt> reads at a higher level of abstraction than <tt>BigDecimal</tt>
 <li>operations on <tt>BigDecimal</tt> can be wrapped to yield a more suitable form for practical use
</ul> 
Here is an example of such a <tt>Money</tt> class. 
<br>
<PRE>

<span class='keyword'>import</span> java.util.*;
<span class='keyword'>import</span> java.io.Serializable;
<span class='keyword'>import</span> java.io.IOException;
<span class='keyword'>import</span> java.io.ObjectInputStream;
<span class='keyword'>import</span> java.io.ObjectOutputStream;
<span class='keyword'>import</span> java.math.BigDecimal;
<span class='keyword'>import</span> <span class='keyword'>static</span> java.math.BigDecimal.ZERO;
<span class='keyword'>import</span> java.math.RoundingMode;

<span class='comment'>/**
* Represent an amount of money in any currency.
*
* &lt;P&gt;This class assumes &lt;em&gt;decimal currency&lt;/em&gt;, without funky divisions 
* like 1/5 and so on. &lt;tt&gt;Money&lt;/tt&gt; objects are immutable. Like {@link BigDecimal}, 
* many operations return new &lt;tt&gt;Money&lt;/tt&gt; objects. In addition, most operations 
* involving more than one &lt;tt&gt;Money&lt;/tt&gt; object will throw a 
* &lt;tt&gt;MismatchedCurrencyException&lt;/tt&gt; if the currencies don't match.
* 
* &lt;h2&gt;Decimal Places and Scale&lt;/h2&gt;
* Monetary amounts can be stored in the database in various ways. Let's take the 
* example of dollars. It may appear in the database in the following ways :
* &lt;ul&gt;
*  &lt;li&gt;as &lt;tt&gt;123456.78&lt;/tt&gt;, with the usual number of decimal places 
*    associated with that currency.
*  &lt;li&gt;as &lt;tt&gt;123456&lt;/tt&gt;, without any decimal places at all.
*  &lt;li&gt;as &lt;tt&gt;123&lt;/tt&gt;, in units of thousands of dollars.
*  &lt;li&gt;in some other unit, such as millions or billions of dollars.
* &lt;/ul&gt;
* 
* &lt;P&gt;The number of decimal places or style of units is referred to as the 
* &lt;em&gt;scale&lt;/em&gt; by {@link java.math.BigDecimal}. This class's constructors 
* take a &lt;tt&gt;BigDecimal&lt;/tt&gt;, so you need to understand it use of the idea of scale.
*  
* &lt;P&gt;The scale can be negative. Using the above examples :
* &lt;table border='1' cellspacing='0' cellpadding='3'&gt;
*  &lt;tr&gt;&lt;th&gt;Number&lt;/th&gt;&lt;th&gt;Scale&lt;/th&gt;&lt;/tr&gt;
*  &lt;tr&gt;&lt;td&gt;123456.78&lt;/th&gt;&lt;th&gt;2&lt;/th&gt;&lt;/tr&gt;
*  &lt;tr&gt;&lt;td&gt;123456&lt;/th&gt;&lt;th&gt;0&lt;/th&gt;&lt;/tr&gt;
*  &lt;tr&gt;&lt;td&gt;123 (thousands)&lt;/th&gt;&lt;th&gt;-3&lt;/th&gt;&lt;/tr&gt;
* &lt;/table&gt;
* 
* &lt;P&gt;Note that scale and rounding are two separate issues.
* In addition, rounding is only necessary for multiplication and division operations.
* It doesn't apply to addition and subtraction.
* 
* &lt;h2&gt;Operations and Scale&lt;/h2&gt;
* &lt;P&gt;Operations can be performed on items having &lt;em&gt;different scale&lt;/em&gt;. 
* For example, these  operations are valid (using an &lt;em&gt;ad hoc&lt;/em&gt; 
* symbolic notation): 
* &lt;PRE&gt;
* 10.plus(1.23) =&gt; 11.23
* 10.minus(1.23) =&gt; 8.77
* 10.gt(1.23) =&gt; true
* 10.eq(10.00) =&gt; true
* &lt;/PRE&gt; 
* This corresponds to typical user expectations. 
* An important exception to this rule is that {@link #equals(Object)} is sensitive 
* to scale (while {@link #eq(Money)} is not) . That is,  
* &lt;PRE&gt;
*   10.equals(10.00) =&gt; false
* &lt;/PRE&gt;
*   
* &lt;h2&gt;Multiplication, Division and Extra Decimal Places&lt;/h2&gt;
* &lt;P&gt;Operations involving multiplication and division are different, since the result
* can have a scale which exceeds that expected for the given currency. For example 
* &lt;PRE&gt;($10.00).times(0.1256) =&gt; $1.256&lt;/PRE&gt;
* which has more than two decimals. In such cases, &lt;em&gt;this class will always round 
* to the expected number of decimal places for that currency.&lt;/em&gt; 
* This is the simplest policy, and likely conforms to the expectations of most 
* end users.
* 
* &lt;P&gt;This class takes either an &lt;tt&gt;int&lt;/tt&gt; or a {@link BigDecimal} for its 
* multiplication and division methods. It doesn't take &lt;tt&gt;float&lt;/tt&gt; or 
* &lt;tt&gt;double&lt;/tt&gt; for those methods, since those types don't interact well with
* &lt;tt&gt;BigDecimal&lt;/tt&gt;. Instead, the &lt;tt&gt;BigDecimal&lt;/tt&gt; class must be used when the 
* factor or divisor is a non-integer.
*  
* &lt;P&gt;&lt;em&gt;The {@link #init(Currency, RoundingMode)} method must be called at least 
* once before using the other members of this class.&lt;/em&gt; It establishes your 
* desired defaults. Typically, it will be called once (and only once) upon startup.
*  
* &lt;P&gt;Various methods in this class have unusually terse names, such as 
* {@link #lt} and {@link #gt}. The intent is that such names will improve the 
* legibility of mathematical expressions. Example : 
* &lt;PRE&gt; if ( amount.lt(hundred) ) {
*     cost = amount.times(price); 
*  }&lt;/PRE&gt;
*/</span>
<span class='keyword'>public</span> <span class='keyword'>final</span> <span class='keyword'>class</span> Money <span class='keyword'>implements</span> Comparable&lt;Money&gt;, Serializable {
  
  <span class='comment'>/**
  * Thrown when a set of  &lt;tt&gt;Money&lt;/tt&gt; objects do not have matching currencies. 
  * 
  * &lt;P&gt;For example, adding together Euros and Dollars does not make any sense.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> <span class='keyword'>final</span> <span class='keyword'>class</span> MismatchedCurrencyException <span class='keyword'>extends</span> RuntimeException { 
    MismatchedCurrencyException(String aMessage){
      <span class='keyword'>super</span>(aMessage);
    }
  }
  
  <span class='comment'>/**
  * Set default values for currency and rounding style.
  * 
  * &lt;em&gt;Your application must call this method upon startup&lt;/em&gt;.
  * This method should usually be called only once (upon startup).
  * 
  * &lt;P&gt;The recommended rounding style is {@link RoundingMode#HALF_EVEN}, also called 
  * &lt;em&gt;banker's rounding&lt;/em&gt;; this rounding style introduces the least bias.
  * 
  * &lt;P&gt;Setting these defaults allow you to use the more terse constructors of this class, 
  * which are much more convenient.
  *  
  * &lt;P&gt;(In a servlet environment, each app has its own classloader. Calling this 
  * method in one app will never affect the operation of a second app running in the same 
  * servlet container. They are independent.)
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> <span class='keyword'>void</span> init(Currency aDefaultCurrency, RoundingMode aDefaultRounding){
    DEFAULT_CURRENCY = aDefaultCurrency;
    DEFAULT_ROUNDING = aDefaultRounding;
  }

  <span class='comment'>/**
  * Full constructor.
  * 
  * @param aAmount is required, can be positive or negative. The number of 
  * decimals in the amount cannot &lt;em&gt;exceed&lt;/em&gt; the maximum number of 
  * decimals for the given {@link Currency}. It's possible to create a 
  * &lt;tt&gt;Money&lt;/tt&gt; object in terms of 'thousands of dollars', for instance. 
  * Such an amount would have a scale of -3.
  * @param aCurrency is required.
  * @param aRoundingStyle is required, must match a rounding style used by 
  * {@link BigDecimal}.
  */</span>
  <span class='keyword'>public</span> Money(BigDecimal aAmount, Currency aCurrency, RoundingMode aRoundingStyle){
    fAmount = aAmount;
    fCurrency = aCurrency;
    fRounding = aRoundingStyle;
    validateState();
  }
  
  <span class='comment'>/**
  * Constructor taking only the money amount. 
  * 
  * &lt;P&gt;The currency and rounding style both take default values.
  * @param aAmount is required, can be positive or negative.
  */</span>
  <span class='keyword'>public</span> Money(BigDecimal aAmount){
    <span class='keyword'>this</span>(aAmount, DEFAULT_CURRENCY, DEFAULT_ROUNDING);
  }
  
  <span class='comment'>/**
  * Constructor taking the money amount and currency. 
  * 
  * &lt;P&gt;The rounding style takes a default value.
  * @param aAmount is required, can be positive or negative.
  * @param aCurrency is required.
  */</span>
  <span class='keyword'>public</span> Money(BigDecimal aAmount, Currency aCurrency){
    <span class='keyword'>this</span>(aAmount, aCurrency, DEFAULT_ROUNDING);
  }
  
  <span class='comment'>/** Return the amount passed to the constructor. */</span>
  <span class='keyword'>public</span> BigDecimal getAmount() { <span class='keyword'>return</span> fAmount; }
  
  <span class='comment'>/** Return the currency passed to the constructor, or the default currency. */</span>
  <span class='keyword'>public</span> Currency getCurrency() { <span class='keyword'>return</span> fCurrency; }
  
  <span class='comment'>/** Return the rounding style passed to the constructor, or the default rounding style. */</span>
  <span class='keyword'>public</span> RoundingMode getRoundingStyle() { <span class='keyword'>return</span> fRounding; }
  
  <span class='comment'>/**
  * Return &lt;tt&gt;true&lt;/tt&gt; only if &lt;tt&gt;aThat&lt;/tt&gt; &lt;tt&gt;Money&lt;/tt&gt; has the same currency 
  * as this &lt;tt&gt;Money&lt;/tt&gt;.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>boolean</span> isSameCurrencyAs(Money aThat){
    <span class='keyword'>boolean</span> result = <span class='keyword'>false</span>;
     <span class='keyword'>if</span> ( aThat != <span class='keyword'>null</span> ) { 
       result = <span class='keyword'>this</span>.fCurrency.equals(aThat.fCurrency);
     }
     <span class='keyword'>return</span> result; 
  }
  
  <span class='comment'>/** Return &lt;tt&gt;true&lt;/tt&gt; only if the amount is positive. */</span>
  <span class='keyword'>public</span> <span class='keyword'>boolean</span> isPlus(){
    <span class='keyword'>return</span> fAmount.compareTo(ZERO) &gt; <span class='literal'>0</span>;
  }
  
  <span class='comment'>/** Return &lt;tt&gt;true&lt;/tt&gt; only if the amount is negative. */</span>
  <span class='keyword'>public</span> <span class='keyword'>boolean</span> isMinus(){
    <span class='keyword'>return</span> fAmount.compareTo(ZERO) &lt;  <span class='literal'>0</span>;
  }
  
  <span class='comment'>/** Return &lt;tt&gt;true&lt;/tt&gt; only if the amount is zero. */</span>
  <span class='keyword'>public</span> <span class='keyword'>boolean</span> isZero(){
    <span class='keyword'>return</span> fAmount.compareTo(ZERO) ==  <span class='literal'>0</span>;
  }
  
  <span class='comment'>/** 
  * Add &lt;tt&gt;aThat&lt;/tt&gt; &lt;tt&gt;Money&lt;/tt&gt; to this &lt;tt&gt;Money&lt;/tt&gt;.
  * Currencies must match.  
  */</span>
  <span class='keyword'>public</span> Money plus(Money aThat){
    checkCurrenciesMatch(aThat);
    <span class='keyword'>return</span> <span class='keyword'>new</span> Money(fAmount.add(aThat.fAmount), fCurrency, fRounding);
  }

  <span class='comment'>/** 
  * Subtract &lt;tt&gt;aThat&lt;/tt&gt; &lt;tt&gt;Money&lt;/tt&gt; from this &lt;tt&gt;Money&lt;/tt&gt;. 
  * Currencies must match.  
  */</span>
  <span class='keyword'>public</span> Money minus(Money aThat){
    checkCurrenciesMatch(aThat);
    <span class='keyword'>return</span> <span class='keyword'>new</span> Money(fAmount.subtract(aThat.fAmount), fCurrency, fRounding);
  }

  <span class='comment'>/**
  * Sum a collection of &lt;tt&gt;Money&lt;/tt&gt; objects.
  * Currencies must match. You are encouraged to use database summary functions 
  * whenever possible, instead of this method. 
  * 
  * @param aMoneys collection of &lt;tt&gt;Money&lt;/tt&gt; objects, all of the same currency.
  * If the collection is empty, then a zero value is returned.
  * @param aCurrencyIfEmpty is used only when &lt;tt&gt;aMoneys&lt;/tt&gt; is empty; that way, this 
  * method can return a zero amount in the desired currency.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> Money sum(Collection&lt;Money&gt; aMoneys, Currency aCurrencyIfEmpty){
    Money sum = <span class='keyword'>new</span> Money(ZERO, aCurrencyIfEmpty);
    <span class='keyword'>for</span>(Money money : aMoneys){
      sum = sum.plus(money);
    }
    <span class='keyword'>return</span> sum;
  }
  
  <span class='comment'>/** 
  * Equals (insensitive to scale).
  * 
  * &lt;P&gt;Return &lt;tt&gt;true&lt;/tt&gt; only if the amounts are equal.
  * Currencies must match. 
  * This method is &lt;em&gt;not&lt;/em&gt; synonymous with the &lt;tt&gt;equals&lt;/tt&gt; method.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>boolean</span> eq(Money aThat) {
    checkCurrenciesMatch(aThat);
    <span class='keyword'>return</span> compareAmount(aThat) == <span class='literal'>0</span>;
  }

  <span class='comment'>/** 
  * Greater than.
  * 
  * &lt;P&gt;Return &lt;tt&gt;true&lt;/tt&gt; only if  'this' amount is greater than
  * 'that' amount. Currencies must match. 
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>boolean</span> gt(Money aThat) { 
    checkCurrenciesMatch(aThat);
    <span class='keyword'>return</span> compareAmount(aThat) &gt; <span class='literal'>0</span>;  
  }
  
  <span class='comment'>/** 
  * Greater than or equal to.
  * 
  * &lt;P&gt;Return &lt;tt&gt;true&lt;/tt&gt; only if 'this' amount is 
  * greater than or equal to 'that' amount. Currencies must match. 
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>boolean</span> gteq(Money aThat) { 
    checkCurrenciesMatch(aThat);
    <span class='keyword'>return</span> compareAmount(aThat) >= <span class='literal'>0</span>;  
  }
  
  <span class='comment'>/** 
  * Less than.
  * 
  * &lt;P&gt;Return &lt;tt&gt;true&lt;/tt&gt; only if 'this' amount is less than
  * 'that' amount. Currencies must match. 
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>boolean</span> lt(Money aThat) { 
    checkCurrenciesMatch(aThat);
    <span class='keyword'>return</span> compareAmount(aThat) &lt; <span class='literal'>0</span>;  
  }
  
  <span class='comment'>/** 
  * Less than or equal to.
  * 
  * &lt;P&gt;Return &lt;tt&gt;true&lt;/tt&gt; only if 'this' amount is less than or equal to
  * 'that' amount. Currencies must match.  
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>boolean</span> lteq(Money aThat) { 
    checkCurrenciesMatch(aThat);
    <span class='keyword'>return</span> compareAmount(aThat) <= <span class='literal'>0</span>;  
  }
  
  <span class='comment'>/**
  * Multiply this &lt;tt&gt;Money&lt;/tt&gt; by an integral factor.
  * 
  * The scale of the returned &lt;tt&gt;Money&lt;/tt&gt; is equal to the scale of 'this' 
  * &lt;tt&gt;Money&lt;/tt&gt;.
  */</span>
  <span class='keyword'>public</span> Money times(<span class='keyword'>int</span> aFactor){  
    BigDecimal factor = <span class='keyword'>new</span> BigDecimal(aFactor);
    BigDecimal newAmount = fAmount.multiply(factor);
    <span class='keyword'>return</span> <span class='keyword'>new</span> Money(newAmount, fCurrency, fRounding);
  }
  
  <span class='comment'>/**
  * Multiply this &lt;tt&gt;Money&lt;/tt&gt; by an non-integral factor (having a decimal point).
  * 
  * &lt;P&gt;The scale of the returned &lt;tt&gt;Money&lt;/tt&gt; is equal to the scale of 
  * 'this' &lt;tt&gt;Money&lt;/tt&gt;. 
  */</span>
  <span class='keyword'>public</span> Money times(<span class='keyword'>double</span> aFactor){
    BigDecimal newAmount = fAmount.multiply(asBigDecimal(aFactor));
    newAmount = newAmount.setScale(getNumDecimalsForCurrency(), fRounding);
    <span class='keyword'>return</span>  <span class='keyword'>new</span> Money(newAmount, fCurrency, fRounding);
  }
  
  <span class='comment'>/**
  * Divide this &lt;tt&gt;Money&lt;/tt&gt; by an integral divisor.
  * 
  * &lt;P&gt;The scale of the returned &lt;tt&gt;Money&lt;/tt&gt; is equal to the scale of 
  * 'this' &lt;tt&gt;Money&lt;/tt&gt;. 
  */</span>
  <span class='keyword'>public</span> Money div(<span class='keyword'>int</span> aDivisor){
    BigDecimal divisor = <span class='keyword'>new</span> BigDecimal(aDivisor);
    BigDecimal newAmount = fAmount.divide(divisor, fRounding);
    <span class='keyword'>return</span> <span class='keyword'>new</span> Money(newAmount, fCurrency, fRounding);
  }

  <span class='comment'>/**
  * Divide this &lt;tt&gt;Money&lt;/tt&gt; by an non-integral divisor.
  * 
  * &lt;P&gt;The scale of the returned &lt;tt&gt;Money&lt;/tt&gt; is equal to the scale of 
  * 'this' &lt;tt&gt;Money&lt;/tt&gt;. 
  */</span>
  <span class='keyword'>public</span> Money div(<span class='keyword'>double</span> aDivisor){  
    BigDecimal newAmount = fAmount.divide(asBigDecimal(aDivisor), fRounding);
    <span class='keyword'>return</span> <span class='keyword'>new</span> Money(newAmount, fCurrency, fRounding);
  }

  <span class='comment'>/** Return the absolute value of the amount. */</span>
  <span class='keyword'>public</span> Money abs(){
    <span class='keyword'>return</span> isPlus() ? <span class='keyword'>this</span> : times(-<span class='literal'>1</span>);
  }
  
  <span class='comment'>/** Return the amount x (-1). */</span>
  <span class='keyword'>public</span> Money negate(){ 
    <span class='keyword'>return</span> times(-<span class='literal'>1</span>); 
  }
  
  <span class='comment'>/**
  * Returns 
  * {@link #getAmount()}.getPlainString() + space + {@link #getCurrency()}.getSymbol().
  * 
  * &lt;P&gt;The return value uses the runtime's &lt;em&gt;default locale&lt;/em&gt;, and will not 
  * always be suitable for display to an end user.
  */</span>
  <span class='keyword'>public</span> String toString(){
    <span class='keyword'>return</span> fAmount.toPlainString() + <span class='literal'>" "</span> + fCurrency.getSymbol();
  }
  
  <span class='comment'>/**
  * Like {@link BigDecimal#equals(java.lang.Object)}, this &lt;tt&gt;equals&lt;/tt&gt; method 
  * is also sensitive to scale.
  * 
  * For example, &lt;tt&gt;10&lt;/tt&gt; is &lt;em&gt;not&lt;/em&gt; equal to &lt;tt&gt;10.00&lt;/tt&gt;
  * The {@link #eq(Money)} method, on the other hand, is &lt;em&gt;not&lt;/em&gt; 
  * sensitive to scale.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>boolean</span> equals(Object aThat){
    <span class='keyword'>if</span> (<span class='keyword'>this</span> == aThat) <span class='keyword'>return</span> <span class='keyword'>true</span>;
    <span class='keyword'>if</span> (! (aThat <span class='keyword'>instanceof</span> Money) ) <span class='keyword'>return</span> <span class='keyword'>false</span>;
    Money that = (Money)aThat;
    <span class='comment'>//the object fields are never null :
</span>    <span class='keyword'>boolean</span> result = (<span class='keyword'>this</span>.fAmount.equals(that.fAmount) );
    result = result &amp;&amp; (<span class='keyword'>this</span>.fCurrency.equals(that.fCurrency) );
    result = result &amp;&amp; (<span class='keyword'>this</span>.fRounding == that.fRounding);
    <span class='keyword'>return</span> result;
  }
  
  <span class='keyword'>public</span> <span class='keyword'>int</span> hashCode(){
    <span class='keyword'>if</span> ( fHashCode == <span class='literal'>0</span> ) {
      fHashCode = HASH_SEED;
      fHashCode = HASH_FACTOR * fHashCode + fAmount.hashCode(); 
      fHashCode = HASH_FACTOR * fHashCode + fCurrency.hashCode();
      fHashCode = HASH_FACTOR * fHashCode + fRounding.hashCode();
    }
    <span class='keyword'>return</span> fHashCode;
  }
  
  <span class='keyword'>public</span> <span class='keyword'>int</span> compareTo(Money aThat) {
    <span class='keyword'>final</span> <span class='keyword'>int</span> EQUAL = <span class='literal'>0</span>;
    
    <span class='keyword'>if</span> ( <span class='keyword'>this</span> == aThat ) <span class='keyword'>return</span> EQUAL;

    <span class='comment'>//the object fields are never null 
</span>    <span class='keyword'>int</span> comparison = <span class='keyword'>this</span>.fAmount.compareTo(aThat.fAmount);
    <span class='keyword'>if</span> ( comparison != EQUAL ) <span class='keyword'>return</span> comparison;

    comparison = <span class='keyword'>this</span>.fCurrency.getCurrencyCode().compareTo(
      aThat.fCurrency.getCurrencyCode()
    );
    <span class='keyword'>if</span> ( comparison != EQUAL ) <span class='keyword'>return</span> comparison;    

    
    comparison = <span class='keyword'>this</span>.fRounding.compareTo(aThat.fRounding);
    <span class='keyword'>if</span> ( comparison != EQUAL ) <span class='keyword'>return</span> comparison;    
    
    <span class='keyword'>return</span> EQUAL;
  }
  
  <span class='comment'>// PRIVATE //
</span>  
  <span class='comment'>/** 
  * The money amount. 
  * Never null. 
  * @serial 
  */</span>
  <span class='keyword'>private</span> BigDecimal fAmount;
  
  <span class='comment'>/** 
  * The currency of the money, such as US Dollars or Euros.
  * Never null. 
  * @serial 
  */</span>
  <span class='keyword'>private</span> <span class='keyword'>final</span> Currency fCurrency;
  
  <span class='comment'>/** 
  * The rounding style to be used. 
  * See {@link BigDecimal}.
  * @serial  
  */</span>
  <span class='keyword'>private</span> <span class='keyword'>final</span> RoundingMode fRounding;
  
  <span class='comment'>/**
  * The default currency to be used if no currency is passed to the constructor. 
  */</span> 
  <span class='keyword'>private</span> <span class='keyword'>static</span> Currency DEFAULT_CURRENCY;
  
  <span class='comment'>/**
  * The default rounding style to be used if no currency is passed to the constructor.
  * See {@link BigDecimal}. 
  */</span> 
  <span class='keyword'>private</span> <span class='keyword'>static</span> RoundingMode DEFAULT_ROUNDING;
  
  <span class='comment'>/** @serial */</span>
  <span class='keyword'>private</span> <span class='keyword'>int</span> fHashCode;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> <span class='keyword'>int</span> HASH_SEED = <span class='literal'>23</span>;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> <span class='keyword'>int</span> HASH_FACTOR = <span class='literal'>37</span>;
  
  <span class='comment'>/**
  * Determines if a deserialized file is compatible with this class.
  *
  * Maintainers must change this value if and only if the new version
  * of this class is not compatible with old versions. See Sun docs
  * for &lt;a href=http://java.sun.com/products/jdk/1.1/docs/guide
  * /serialization/spec/version.doc.html&gt; details. &lt;/a&gt;
  *
  * Not necessary to include in first version of the class, but
  * included here as a reminder of its importance.
  */</span>
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> <span class='keyword'>long</span> serialVersionUID = <span class='literal'>7526471155622776147L</span>;

  <span class='comment'>/**
  * Always treat de-serialization as a full-blown constructor, by
  * validating the final state of the de-serialized object.
  */</span>  
  <span class='keyword'>private</span> <span class='keyword'>void</span> readObject(
    ObjectInputStream aInputStream
  ) <span class='keyword'>throws</span> ClassNotFoundException, IOException {
    <span class='comment'>//always perform the default de-serialization first
</span>    aInputStream.defaultReadObject();
    <span class='comment'>//defensive copy for mutable date field
</span>    <span class='comment'>//BigDecimal is not technically immutable, since its non-final
</span>    fAmount = <span class='keyword'>new</span> BigDecimal( fAmount.toPlainString() );
    <span class='comment'>//ensure that object state has not been corrupted or tampered with maliciously
</span>    validateState();
  }

  <span class='keyword'>private</span> <span class='keyword'>void</span> writeObject(ObjectOutputStream aOutputStream) <span class='keyword'>throws</span> IOException {
    <span class='comment'>//perform the default serialization for all non-transient, non-static fields
</span>    aOutputStream.defaultWriteObject();
  }  

  <span class='keyword'>private</span> <span class='keyword'>void</span> validateState(){
    <span class='keyword'>if</span>( fAmount == <span class='keyword'>null</span> ) {
      <span class='keyword'>throw</span> <span class='keyword'>new</span> IllegalArgumentException(<span class='literal'>"Amount cannot be null"</span>);
    }
    <span class='keyword'>if</span>( fCurrency == <span class='keyword'>null</span> ) {
      <span class='keyword'>throw</span> <span class='keyword'>new</span> IllegalArgumentException(<span class='literal'>"Currency cannot be null"</span>);
    }
    <span class='keyword'>if</span> ( fAmount.scale() &gt; getNumDecimalsForCurrency() ) {
      <span class='keyword'>throw</span> <span class='keyword'>new</span> IllegalArgumentException(
        <span class='literal'>"Number of decimals is "</span> + fAmount.scale() + <span class='literal'>", but currency only takes "</span> + 
        getNumDecimalsForCurrency() + <span class='literal'>" decimals."</span>
      );    
    }
  }
  
  <span class='keyword'>private</span> <span class='keyword'>int</span> getNumDecimalsForCurrency(){
    <span class='keyword'>return</span> fCurrency.getDefaultFractionDigits();
  }
  
  <span class='keyword'>private</span> <span class='keyword'>void</span> checkCurrenciesMatch(Money aThat){
    <span class='keyword'>if</span> (! <span class='keyword'>this</span>.fCurrency.equals(aThat.getCurrency())) {
       <span class='keyword'>throw</span> <span class='keyword'>new</span> MismatchedCurrencyException(
         aThat.getCurrency() + <span class='literal'>" doesn't match the expected currency : "</span> + fCurrency
       ); 
    }
  }
  
  <span class='comment'>/** Ignores scale: 0 same as 0.00 */</span>
  <span class='keyword'>private</span> <span class='keyword'>int</span> compareAmount(Money aThat){
    <span class='keyword'>return</span> <span class='keyword'>this</span>.fAmount.compareTo(aThat.fAmount);
  }
  
  <span class='keyword'>private</span> BigDecimal asBigDecimal(<span class='keyword'>double</span> aDouble){
    String asString = Double.toString(aDouble);
    <span class='keyword'>return</span> <span class='keyword'>new</span> BigDecimal(asString);
  }
} 
</PRE>
<br>
<br>
<br>

</div>




<div class='topic-section'>See Also :</div>
<div class='main-body'>
 
  
  <a href='TopicActionb0f5-2.html?Id=213'>Beware of floating point numbers</a> <br>
 
</div>


<div class='topic-section'>Would you use this technique?</div>
<div class='main-body'>
  
  <form action="http://www.javapractices.com/vote/AddVoteAction.do" method='post'>
    Yes<input type='radio' name='Choice' value='Y' >
    &nbsp;&nbsp;No<input type='radio' name='Choice' value='N'>
    &nbsp;&nbsp;Undecided<input type='radio' name='Choice' value="?" >
    &nbsp;&nbsp;<input type=submit value="Vote" >
    <input type='hidden' name='Operation' value='Apply'>
    <input type='hidden' name='TopicId' value='13'>
  </form>
</div>

<div style='height:10.0em;'></div>

 
 
</div>

  

 





<div align='center' class='legalese'>  
&copy; 2011 Hirondelle Systems |
<a href='../source/SourceAction-2.html'><b>Source Code</b></a><IMG class='no-margin' SRC="../images/goldstar.gif" ALT=""> |
<a href="mailto:webmaster@javapractices.com">Contact</a> |
<a href="http://creativecommons.org/licenses/by-nc-sa/1.0/">License</a> |
<a href='../apps/cjp.rss'>RSS</a>
<!-- ukey="2AC36CD2" -->
<!-- ckey="16DF3D87" -->
<br>

 Individual code snippets can be used under this <a href='../LICENSE.txt'>BSD license</a> - Last updated on June 6, 2010.<br>
 Over 150,000 unique IPs last month - <span title='Java Practices 2.6.5, Mon May 16 00:00:00 EDT 2011'>Built with</span> <a href='http://www.web4j.com/'>WEB4J</a>.<br>
 - In Memoriam : Bill Dirani -
</div>

<script src="../../www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-2633428-1";
urchinTracker();
</script>



</body>

<!-- Mirrored from www.javapractices.com/topic/TopicAction.do;jsessionid=4FCCB481C702D708A7360133D128E359?Id=13 by HTTrack Website Copier/3.x [XR&CO'2010], Sun, 12 Jun 2011 17:27:39 GMT -->
<!-- Added by HTTrack --><meta http-equiv="content-type" content="text/html;charset=UTF-8"><!-- /Added by HTTrack -->
</html>
